﻿using System;
using System.Collections;
using System.Collections.Specialized;
using System.Data;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BdiSyndicatonWarmup
{
    public partial class WarmUp : Form
    {
        private DataTable dtRequest = new DataTable();
        private string folderName = "csvfile";
        private delegate void DispResponseDelegate(string machineName, IBdiHttpWebResponse bdiResponse);
        CancellationTokenSource cts;
        System.Threading.Timer timer;
        AutoSizeFormClass asc = new AutoSizeFormClass();

        private delegate void UpdateResposeResultEventHandler(string machineName, IBdiHttpWebResponse bdiResponse);

        public WarmUp()
        {
            InitializeComponent();

            Initialize();
        }

        private void cmbRequest_SelectedIndexChanged(object sender, EventArgs e)
        {
            int index = cmbRequest.SelectedIndex;

            if (index < dtRequest.Rows.Count)
            {
                txtHeaders.Text = dtRequest.Rows[index][1].ToString();
                txtBody.Text = dtRequest.Rows[index][2].ToString();
            }
        }

        private void lstCsvFile_SelectedIndexChanged(object sender, EventArgs e)
        {
            cklUrlList.Items.Clear();
            for (int i = 0; i < lstCsvFile.Items.Count; i++)
            {
                if (lstCsvFile.GetSelected(i))
                {
                    ArrayList list = BdiFileRead.ReadMachineNameFromCsvFile(folderName + "\\" + lstCsvFile.Items[i].ToString());

                    foreach (string machineName in list)
                    {
                        cklUrlList.Items.Add("http://" + machineName + "/bdisyn/v2/");
                    }
                }
            }

        }

        private void btnAllSelect_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < cklUrlList.Items.Count; i++)
            {
                if (!cklUrlList.GetItemChecked(i))
                {
                    cklUrlList.SetItemChecked(i, true);
                }
            }
        }

        private void btnAllCancel_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < cklUrlList.Items.Count; i++)
            {
                if (cklUrlList.GetItemChecked(i))
                {
                    cklUrlList.SetItemChecked(i, false);
                }
            }
        }

        private void btnExecute_Click(object sender, EventArgs e)
        {
            if (ckbUrl.Checked)
            {
                if (string.IsNullOrEmpty(txtUrl.Text.ToString().Trim()))
                {
                    MessageBox.Show("Please enter Url.");
                    txtUrl.Focus();
                    return;
                }
            }
            else
            {
                bool isSelect = false;
                for (int i = 0; i < cklUrlList.Items.Count; i++)
                {
                    if (cklUrlList.GetItemChecked(i))
                    {
                        isSelect = true;
                        break;
                    }
                }
                if (!isSelect)
                {
                    MessageBox.Show("Please select send url.");
                    cklUrlList.Focus();
                    return;
                }
            }

            if (string.IsNullOrEmpty(txtHeaders.Text.Trim()))
            {
                MessageBox.Show("Please enter Request Headers.");
                txtHeaders.Focus();
                return;
            }

            if (string.IsNullOrEmpty(txtBody.Text.Trim()))
            {
                MessageBox.Show("Please enter Request Body.");
                txtBody.Focus();
                return;
            }

            if (rdbQps.Checked && ckbUrl.Checked)
            {
                btnExecute.Enabled = false;
                btnOne.Enabled = false;
                btnExecute.Text = "Executing";
                ckbUrl.Enabled = false;
            }

            SendRequest();
        }

        private void txtHeaders_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Modifiers == Keys.Control && e.KeyCode == Keys.A)
            {
                ((TextBox)sender).SelectAll();
            }
        }

        private void txtBody_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Modifiers == Keys.Control && e.KeyCode == Keys.A)
            {
                ((TextBox)sender).SelectAll();
            }
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            lstResposeResult.Items.Clear();
            txt200.Text = "0";
            txt400.Text = "0";
            txt500.Text = "0";
        }

        private void WarmUp_Load(object sender, EventArgs e)
        {
            asc.ControllInitializeSize(this);
        }

        private void WarmUp_SizeChanged(object sender, EventArgs e)
        {
            asc.ControlAutoSize(this);            
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
            }
            if (timer != null)
            {
                timer.Dispose();
            }

            if (!btnExecute.Enabled)
            {
                btnExecute.Enabled = true;
                btnExecute.Text = "Execute";
                btnOne.Enabled = false;
            }
            if (!btnOne.Enabled)
            {
                btnOne.Enabled = true;
            }
            if (!ckbUrl.Enabled)
            {
                ckbUrl.Enabled = true;
            }
        }

        private void btnOne_Click(object sender, EventArgs e)
        {
            if (ckbUrl.Checked)
            {
                if (string.IsNullOrEmpty(txtUrl.Text.ToString().Trim()))
                {
                    MessageBox.Show("Please enter Url.");
                    txtUrl.Focus();
                    return;
                }
            }
            else
            {
                bool isSelect = false;
                for (int i = 0; i < cklUrlList.Items.Count; i++)
                {
                    if (cklUrlList.GetItemChecked(i))
                    {
                        isSelect = true;
                        break;
                    }
                }
                if (!isSelect)
                {
                    MessageBox.Show("Please select send url.");
                    cklUrlList.Focus();
                    return;
                }
            }

            if (string.IsNullOrEmpty(txtHeaders.Text.Trim()))
            {
                MessageBox.Show("Please enter Request Headers.");
                txtHeaders.Focus();
                return;
            }

            if (string.IsNullOrEmpty(txtBody.Text.Trim()))
            {
                MessageBox.Show("Please enter Request Body.");
                txtBody.Focus();
                return;
            }

            SendOnceRequest();
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog dialog = new OpenFileDialog())
            {
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    txtQueryFile.Text = dialog.FileName;
                }
            }
        }

        private void ckbUrl_CheckedChanged(object sender, EventArgs e)
        {
            if (ckbUrl.Checked)
            {
                rdbQps.Enabled = true;
                numQps.Enabled = true;
            }
            else
            {
                if (rdbQps.Checked)
                {
                    rdbTimes.Checked = true;
                    rdbQps.Checked = false;
                }
                rdbQps.Enabled = false;
                numQps.Enabled = false;
            }
        }

        private void Initialize()
        {
            try
            {
                // Initialize csv file list 
                lstCsvFile.DataSource = BdiFileRead.GetCsvFileName(folderName);
                txtQueryFile.Text = BdiFileRead.GetQueryFileName();

                // Initialize Request Template 
                dtRequest = BdiXmlRead.ReadXmlData("RequestTemplate.xml");
                cmbRequest.DisplayMember = "name";
                cmbRequest.DataSource = dtRequest;
                cmbRequest.SelectedIndex = 0;

                // Initialize Transmission times
                numTime.Value = 10;

                // Initialize Respose Result list
                lstResposeResult.GridLines = true;
                lstResposeResult.FullRowSelect = true;
                lstResposeResult.View = View.Details;
                lstResposeResult.Scrollable = true;
                lstResposeResult.MultiSelect = false;
                lstResposeResult.HeaderStyle = ColumnHeaderStyle.Clickable;

                lstResposeResult.Columns.Add("#", 60, HorizontalAlignment.Center);
                lstResposeResult.Columns.Add("HttpStatusCode", 100, HorizontalAlignment.Center);
                lstResposeResult.Columns.Add("Host", 120, HorizontalAlignment.Center);
                lstResposeResult.Columns.Add("ResponseLatency", 100, HorizontalAlignment.Center);

                lstResposeResult.Visible = true;
                if (!ckbUrl.Checked)
                {
                    rdbQps.Enabled = false;
                    numQps.Enabled = false;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void SendRequest()
        {
            try
            {
                ArrayList list = new ArrayList();
                if (ckbUrl.Checked)
                {
                    string strUrl = txtUrl.Text.ToString().Trim();
                    if (!strUrl.StartsWith("http://") && !strUrl.StartsWith("https://"))
                    {
                        strUrl = "http://" + strUrl;
                    }
                    list.Add(strUrl);
                }
                else
                {
                    for (int i = 0; i < cklUrlList.Items.Count; i++)
                    {
                        if (!cklUrlList.GetItemChecked(i))
                        {
                            continue;
                        }
                        string url = cklUrlList.Items[i].ToString();
                        list.Add(url);
                    }
                }

                string requestBody = txtBody.Text.Trim();
                NameValueCollection requestHeader = GetRequestHeaders();
                cts = new CancellationTokenSource();
                ArrayList listQuery = new ArrayList(); 
                if (!string.IsNullOrEmpty(txtQueryFile.Text))
                {
                    listQuery = BdiFileRead.GetFileName(txtQueryFile.Text);
                }

                if (rdbQps.Checked)
                {
                    int qps = (int)numQps.Value;
                    foreach (string strUrl in list)
                    {
                        string machineName = strUrl.Substring(strUrl.IndexOf("//") + 2, strUrl.Substring(strUrl.IndexOf("//") + 2).IndexOf("/"));
                
                        IBdiRequeParameters requestParameters = new IBdiRequeParameters();
                        requestParameters.RequestHeaders = requestHeader;
                        requestParameters.RequestBody = requestBody;
                        requestParameters.Url = strUrl;
                        requestParameters.QPS = qps;
                        requestParameters.MachineName = machineName;
                        requestParameters.QueryList = listQuery;
                        timer = new System.Threading.Timer(SendRequestQpsThread, requestParameters, 0, 1000);
                    }
                }
                else if (rdbTimes.Checked)
                {
                    int count = (int)numTime.Value;
                    foreach (string strUrl in list)
                    {
                        string machineName = strUrl.Substring(strUrl.IndexOf("//") + 2, strUrl.Substring(strUrl.IndexOf("//") + 2).IndexOf("/"));
                
                        IBdiRequeParameters requestParameters = new IBdiRequeParameters();
                        requestParameters.RequestHeaders = requestHeader;
                        requestParameters.RequestBody = requestBody;
                        requestParameters.Count = count;
                        requestParameters.Url = strUrl;
                        requestParameters.MachineName = machineName;
                        requestParameters.QueryList = listQuery;
                        Task t = new Task(() => SendRequestThread(requestParameters, cts.Token));
                        t.Start();
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private NameValueCollection GetRequestHeaders()
        {
            NameValueCollection requestHeaders = new NameValueCollection();
            string[] headers = txtHeaders.Lines.Select(x => x.Trim()).ToArray();
            foreach (string header in headers)
            {
                if (string.IsNullOrEmpty(header))
                {
                    continue;
                }
                string[] data = header.Split(':');
                if (data.Length < 2)
                {
                    continue;
                }
                requestHeaders.Add(data[0], data[1]);
            }
            return requestHeaders;
        }

        private void UpdateResposeResult(string machineName, IBdiHttpWebResponse bdiResponse)
        {
            lock (lstResposeResult)
            {
                lstResposeResult.BeginUpdate();
                ListViewItem Item = new ListViewItem();
                Item.SubItems[0].Text = lstResposeResult.Items.Count.ToString();
                Item.SubItems.Add(bdiResponse.StatusCode);
                Item.SubItems.Add(machineName);
                Item.SubItems.Add(bdiResponse.RequestStreamLatency.ToString());

                lstResposeResult.Items.Add(Item);
                lstResposeResult.EndUpdate();
                lstResposeResult.Items[lstResposeResult.Items.Count - 1].EnsureVisible();
            }
            if (bdiResponse.StatusCode == "200")
            {
                lock (txt200)
                {
                    txt200.Text = (Convert.ToInt32(txt200.Text) + 1).ToString();
                    txt200.Update();
                }
            }
            else if(bdiResponse.StatusCode.StartsWith("4"))
            {
                lock (txt400)
                {
                    txt400.Text = (Convert.ToInt32(txt400.Text) + 1).ToString();
                    txt400.Update();
                }
            }
            else if (bdiResponse.StatusCode.StartsWith("5"))
            {
                lock (txt500)
                {
                    txt500.Text = (Convert.ToInt32(txt500.Text) + 1).ToString();
                    txt500.Update();
                }
            }
        }

        private void SendOnceRequest()
        {
            try
            {
                ArrayList list = new ArrayList();

                if (ckbUrl.Checked)
                {
                    string strUrl = txtUrl.Text.ToString().Trim();
                    if (!strUrl.Contains("http://") && !strUrl.Contains("https://"))
                    {
                        strUrl = "http://" + strUrl;
                    }
                    list.Add(strUrl);
                }
                else
                {
                    for (int i = 0; i < cklUrlList.Items.Count; i++)
                    {
                        if (!cklUrlList.GetItemChecked(i))
                        {
                            continue;
                        }
                        string url = cklUrlList.Items[i].ToString();
                        list.Add(url);
                    }
                }

                string requestBody = txtBody.Text.Trim();
                NameValueCollection requestHeader = GetRequestHeaders();

                ArrayList listQuery = new ArrayList();
                if (!string.IsNullOrEmpty(txtQueryFile.Text))
                {
                    listQuery = BdiFileRead.GetFileName(txtQueryFile.Text);
                }

                foreach (string strUrl in list)
                {
                    string machineName = strUrl.Substring(strUrl.IndexOf("//") + 2, strUrl.Substring(strUrl.IndexOf("//") + 2).IndexOf("/"));
                
                    IBdiRequeParameters requestParameters = new IBdiRequeParameters();
                    requestParameters.RequestHeaders = requestHeader;
                    requestParameters.RequestBody = requestBody;
                    requestParameters.Url = strUrl;
                    requestParameters.MachineName = machineName;
                    requestParameters.QueryList = listQuery;
                    Task t = new Task(() => SendOnceRequestThread(requestParameters, cts.Token));
                    t.Start();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void SendOnceRequestThread(IBdiRequeParameters requestParameter, CancellationToken ct)
        {
            try
            {
                if (ct.IsCancellationRequested)
                {
                    return;
                }
                requestParameter.RequestBody = GetRequestBody(requestParameter);
                Task<IBdiHttpWebResponse> bdiResponseTask = BdiHttpWebRequest.CreatePostHttpResponse(requestParameter);

                bdiResponseTask.ContinueWith(t =>
                {
                    this.Invoke(new UpdateResposeResultEventHandler(UpdateResposeResult), new object[] { requestParameter.MachineName, t.Result });
                });
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void SendRequestThread(IBdiRequeParameters requestParameter, CancellationToken ct)
        {
            try
            {
                for (int j = 0; j < requestParameter.Count; j++)
                {
                    if (ct.IsCancellationRequested)
                    {
                        break;
                    }
                    requestParameter.RequestBody = GetRequestBody(requestParameter);
                    Task<IBdiHttpWebResponse> bdiResponseTask = BdiHttpWebRequest.CreatePostHttpResponse(requestParameter);

                    bdiResponseTask.ContinueWith(t =>
                    {
                        this.Invoke(new UpdateResposeResultEventHandler(UpdateResposeResult), new object[] { requestParameter.MachineName, t.Result });
                    });
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void SendRequestQpsThread(object state)
        {
            try
            {
                IBdiRequeParameters requestParameter = (IBdiRequeParameters)state;
                for (int i = 0; i < requestParameter.QPS; i++)
                {
                    if (cts.Token.IsCancellationRequested)
                    {
                        break;
                    }
                    Task t = new Task(() => SendOnceRequestQpsThread(requestParameter), cts.Token);
                    t.Start();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void SendOnceRequestQpsThread(IBdiRequeParameters requestParameter)
        {
            requestParameter.RequestBody = GetRequestBody(requestParameter);
            Task<IBdiHttpWebResponse> bdiResponseTask = BdiHttpWebRequest.CreatePostHttpResponse(requestParameter);
            bdiResponseTask.ContinueWith(t =>
            {
                //this.Invoke(new UpdateResposeResultEventHandler(UpdateResposeResult), new object[] { requestParameter.MachineName, t.Result });
            });
        }

        private string GetRequestBody(IBdiRequeParameters requestParameter)
        {
            if (requestParameter.QueryList.Count > 0)
            {
                Random rand = new Random();
                int index = rand.Next(0, requestParameter.QueryList.Count - 1);
                string query = requestParameter.QueryList[index].ToString();

                int start = requestParameter.RequestBody.IndexOf("<bdi:Query>");
                int end = requestParameter.RequestBody.IndexOf("</bdi:Query>");
                if (start > 0 && end > 0)
                {
                    return requestParameter.RequestBody.Substring(0, start) + "<bdi:Query>" + query + requestParameter.RequestBody.Substring(end);
                }
            }
            return requestParameter.RequestBody;
        }
    }
}
